"""Global variables and methods to use game-wide game module,
manages the things that have to happen in the main loop"""
import random, pygame
from OpenGL.GL import *
from OpenGL.GLU import *
import resource_manager
import gl
from math import *
from vecmath import *
from pygame.locals import *

font = fpscounter = display = None
mission = 0
ships = bullets = particles = stars = None
rwidth = rx = ry = rfact = arrow = radar = radar_color = 0
cam = dimensions = None
vp = [0, 0]
zoom = 1
delta = 0
_debug = ['']
_debug_changed = 1
         
def init(display_size, display_flags):
    """Basic initialization of the game"""
    global display, dimensions, rwidth, rx, ry, rfact, arrow, radar, radar_color
    
    display = pygame.display.set_mode(display_size, display_flags)
    print '========== INFO: =========='
    print 'Driver: '+pygame.display.get_driver()
    print pygame.display.Info()
    print '==========================='
    dimensions = Rect((0, 0), display_size)
    
    # stuff for the radar to draw
    rwidth = 100
    rx, ry = dimensions.bottomright[0] - rwidth - 10, dimensions.bottomright[1] - rwidth - 10
    rfact = rwidth / (sqrt(dimensions.w**2 + dimensions.h**2) * 3)
    arrow = gl.GLSurface(resource_manager.load_image('arrow.png'), center=False)
    radar = gl.GLSurface(resource_manager.load_image('radar.png'))
    radar_color = (0, 0, 1, 1)
    
def update_groups(delta):
    """Called each tick, updates the srpite groups
    Delta is the fraction of a full tick that has elapsed since last update,
    passed to avoid actions ocurring faster than they should if wer are lagging"""
    cam.update()
    ships.update(delta)
    bullets.update(delta)
    particles.update(delta)
    stars.update(cam.speed(), zoom)
    mission.tick()
    
def redraw():
    """Clears and redraws every element of the game that should be drawn"""
    # drawing the gui took too long to be done every tick
    # TODO more elegant way of doing this
    gui_due=0
    #if(pygame.time.get_ticks() > next_effects_clear):
    #    gui_due = 1
    _clear()
    stars.draw()
    
    glEnable(GL_TEXTURE_2D)
    bullets.draw(dimensions)
    ships.draw(dimensions)
    particles.draw(dimensions)
    mission.draw(dimensions)
    
    _drawstring(fpscounter, (0, 0))
    _drawstring(str(zoom) + 'X', (0, 20))
    _drawstring(str(len(ships)) + ' ships', (0, 40))
    _drawstring(str(len(bullets)) + ' bullets', (0, 60))
    _drawstring(str(len(particles)) + ' particles', (0, 80))
    _drawstring(str(len(particles) + len(bullets) + len(ships)) + ' total', (0, 100))
    _draw_radar()
    cx = 0
    hd = 20 * len(_debug)
    cy = dimensions.h - hd
    # console
    l = 0
    for s in _debug:
        font.render(s, (0, l))
        l+=font.line_heigth
    font.render(str(dist((0, 0), cam.speed())), (0, 100))
    glDisable(GL_TEXTURE_2D)
    
    
    glLoadIdentity()
    glTranslate(dimensions.w - 150, 0, 0)
    s = cam.sprite
    glLineWidth(10)
    glBegin(GL_LINES)
    glColor3f(1, 1, 1)
    glVertex2f(10, 10)
    glColor3f(0, 1, 0)
    glVertex2f(10+s.health, 10)
    glColor3f(1, 1, 1)
    glVertex2f(10, 25)
    glColor3f(1, 0, 0)
    glVertex2f(10+s.next_sec, 25)
    glEnd()
    
    pygame.display.flip() # paste everything to the screen
    
def _drawstring(string, pos):
    """Draws an string in the given position to the given surface"""
    font.render(string, (pos[0], dimensions.h - pos[1] - font.line_heigth))
    #surface.blit(font.render(string, 1, (255, 255, 255)), pos)

def _clear():
    """Clears the screen and the effects layer if due"""
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
                
def _draw_radar():
    """Polls every ship for its position
    and draws them scaled to some sort of radar"""
    radar.draw((rx, ry), tint=radar_color)

    ox, oy = cam.position()
    for sprite in ships:
        dx, dy = sprite.position
        d = dist((ox, oy), (dx, dy))
        if d == 0: # is self or over (and you dont need to see this in a radar)
            continue
        
        ang = atan2(dy - oy, dx - ox) # angle the boogie is
        if (d * rfact) > rwidth: # if it's farther the radar can draw it, stick to the border
            x = rx + cos(ang) * rwidth - 5
            y = ry + sin(ang) * rwidth - 5
            font.render(str(int(d)), (x + 10, y))
        else:
            x = rx + cos(ang) * d * rfact - 5 
            y = ry + sin(ang) * d * rfact - 5
        
        if sprite.__module__ == 'vessels.colonial':
            arrow.draw((x, y), tint=(0, 0, 1, 1))
        else:
            arrow.draw((x, y), tint=(1, 0, 0, 1))
        
        
def _draw_gui(surface):
    """draws info to the screen"""
    s = cam.speed()
    _drawstring(surface, sqrt(s[0] * s[0] + s[1] * s[1]).__str__(), (400, 40))
    try:
        surface.fill((255, 0, 0), (dimensions.w - 100, 10, cam.sprite.next_sec, 20))
    except:
        pass
    _drawstring(zoom.__str__()+'X', (0, 20))
    _drawstring(len(ships).__str__()+' ships', (0, 40))
    _drawstring(len(bullets).__str__()+' bullets', (0, 60))
    _drawstring(len(particles).__str__()+' particles', (0, 80))

def debug(str):
    """Prints to the screen the given string, debug or chat purposes"""
    print str
    _debug.insert(0,pygame.time.get_ticks().__str__() + ': ' + str.__str__())
    if len(_debug) > 5:
        _debug.pop()

class Controller:
    """Base controller class"""
    _action_map = {'acc':0, 'dec':1, 'left':2, 'right':3, 'prim':4, 'sec':5}
    def __init__(self, ship):
        """ship: the ship to control"""
        self.ship = ship
        self.actions = [0]*6
    def actionmask(self):
        """Converts the boolean action list as a masked long"""
        l = 0
        i = 1
        for e in self.actions:
            if e:
                l |= i
            i <<= 1
        return l
    def onhit(self, by, delta = 1):
        """Respond to fire
        bullet is the bullet that did hit us
        delta is the fraction of a game tick that went last time"""
        pass
    def control(self, delta):
        """Perform actions for this tick, poll for keys, make decisions
        or whathever needs to happen every tick
        
        delta is the fraction of a game tick that went last time"""
        pass